/**
	@file gps.h
	@brief Header for GPS utility library gps.cpp
*/
#ifndef gps_h
/** @def gps_h
	@brief Library included tag
*/
#define gps_h

#include "gps_setup.h"
#include "Arduino.h"

#ifndef pi
/**
	@def pi
	@brief pi
*/
#define pi 3.14159265
#endif

#ifndef R
/**
	@def R
	@brief Earth's radius
*/
#define R 6371
#endif

// NMEA TYPE //////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
	@def NMEA_RMC
	@brief NMEA TYPE RMC
	@details NMEA TYPE RMC, Recommended minimum data. http://www.gpsinformation.org/dale/nmea.htm#RMC
*/
#define NMEA_RMC 		1

/**
	@def NMEA_PMTKCHN
	@brief NMEA TYPE MTK CHN
	@details NMEA TYPE MTK CHN, GPS Channel information. http://snoob-community.wikispaces.com/PMTKCHN
*/
#define NMEA_PMTKCHN	2

/**
	@def NMEA_GPZDA
	@brief NMEA TYPE ZDA
	@details NMEA TYPE ZDA, Date and Time data. In this NMEA string the year has 4 character.
*/
#define NMEA_GPZDA		3


// ERROR //////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
	@def NMEA_ERR_FORMAT
	@brief format error
	@details NMEA string has wrong format.
*/
#define NMEA_ERR_FORMAT		(-1)

/**
	@def NMEA_ERR_CHECKSUM
	@brief checksum error
	@details NMEA string has failed the checksum.
*/
#define NMEA_ERR_CHECKSUM	(-2)


// VALID //////////////////////////////////////////////////////////////////////////////////////////////////////////////

/** @def VALID_ACTIVE
	@brief Validity Active
	@details Validity Active. Used to check the validity of the GPS information.
*/
#define VALID_ACTIVE	0x41

/** @def VALID_VOID
	@brief Validity Void
	@details Validity Void. Used to check the validity of the GPS information.
*/
#define VALID_VOID		0x56


// FIX MODE ///////////////////////////////////////////////////////////////////////////////////////////////////////////

/** @def MODE_AUTONOMOUS
	@brief GPS fix mode Autonomous
	@details The GPS fix was done in mode Autonomous. This define is used in to check the mode in GpsInfo_s.mode
*/
#define MODE_AUTONOMOUS		0x41

/** @def MODE_DIFFERENTIAL
	@brief GPS fix mode Defferential
	@details The GPS fix was done in mode Defferential. This define is used in to check the mode in GpsInfo_s.mode
*/
#define MODE_DIFFERENTIAL	0x44

/** @def MODE_ESTIMATED
	@brief GPS fix mode Estimated
	@details The GPS fix was done in mode Estimated. This define is used in to check the mode in GpsInfo_s.mode
*/
#define MODE_ESTIMATED		0x45



// $PMTKCHN ///////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef PMTKCHN_ENABLE

	/** @def TOTAL_CHANNEL
		@brief Total number of channel on the GPS device.
		@details This define can be set in gps_setup.h. If it is not set or set to 0 or below, it will be set to its default value of 66.
	*/
	#ifndef TOTAL_CHANNEL
		#define TOTAL_CHANNEL (66)
	#endif
	#if TOTAL_CHANNEL <= 0
		#define TOTAL_CHANNEL (66)
	#endif
	
	/** @def STATUS_CHN_IDLE
		@brief Channel Status Idle
	*/
	#define STATUS_CHN_IDLE 		0
	
	/** @def STATUS_CHN_SEARCHING
		@brief Channel Status Searching
	*/
	#define STATUS_CHN_SEARCHING	1
	
	/** @def STATUS_CHN_TRACKING
		@brief Channel Status Tracking
	*/
	#define STATUS_CHN_TRACKING		2
#endif


// CLASS //////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
	@class gps gps.h "gps.h"
	@brief gps class
	@details The gps class is a collection of tool to deal with gps and navigation data.
*/
class gps
{
	public:
		gps();
		/**
			@var valid
			@brief validity tag
			@details This vriable indicate if the gps data are Active or Void. use the define VALID_ACTIVE and VALID_VOID to check the validity.
		*/
		int valid;
		
		/**
			@struct RMCstr gps.h "gps.h"
			@brief Struct to work with $GPRMC string.
			@details This structure contain all the sub element in an NMEA RMC string.
		*/
		struct RMCstr
		{
			/** @var time
			NMEA RMC Time String */
			char *time;
			
			/** @var valid
			char that represent the validity.*/
			char valid;
			
			/** @var lat
			NMEA RMC Latitude string */
			char *lat;
			
			/** @var latNS
			char North or South */
			char latNS;
			
			/** @var lon
			NMEA RMC Longitude string */
			char *lon;
			
			/** @var lonEW
			char East 'E' or West 'W' */
			char lonEW;
			
			/** @var knots
			float NMEA RMC Knots */
			float knots;
			
			/** @var course
			float NMEA RMC Course */
			float course;
			
			/** @var date
			NMEA RMC Date string */
			char *date;
			
			/** @var magvar
			float NMEA RMC Magnetic Variation */
			float magvar;
			
			/** @var magvarEW
			char NMEA RMC Magnetic variation Cardinal direction, East 'E' or West 'W' */
			char magvarEW;
			/** @var mode
			char NMEA RMC Fix mode. Use the define MODE_AUTONOMOUS, MODE_DIFFERENTIAL or MODE_ESTIMATED */
			char mode;
		};
		
		/**
			@struct time_s gps.h "gps.h"
			@brief time struct
			@details This structure is used to work with time information.
		*/
		struct time_s
		{
			/** @var h
			Hours */
			int h;
			
			/** @var m
			Minutes */
			int m;
			
			/** @var s
			Seconds */
			int s;
			
			/** @var ms
			miliseconds */
			int ms;
		};
		
		/**
			@struct date_s gps.h "gps.h"
			@brief date struct
			@details This structure is to work with date information.
		*/
		struct date_s
		{
			/** @var d
			Day */
			int d;
			
			/** @var m
			Month */
			int m;
			
			/** @var y
			Year. Depending on the NMEA string that are enabled, the year can be YY or YYYY. */
			int y;
		};
		
		/**
			@struct GpsInfo_s gps.h "gps.h"
			@brief General gps info
			@details This structure is made to contain the process gps information.
		*/
		struct GpsInfo_s
		{
			/** @var time
			GPS Information time. See time_s info. */
			time_s time;
			
			/** @var date
			GPS Information date. See date_s info. */
			date_s date;
			
			/** @var latd
			GPS Information Latitude in Degree.Decimal. */
			float latd;
			
			/** @var lond
			GPS Information Longitude in Degree.Decimal
			*/
			float lond;
			
			/** @var knots
			GPS Information speed in Knots */
			float knots;
			
			/** @var course
			GPS Information course in Degree.Decimal */
			float course;
			
			/** magvar
			GPS Information magnetic variation in Degree.Decimal */
			float magvar;
			
			/** mode
			GPS Information Fix Mod. Use the define MODE_AUTONOMOUS, MODE_DIFFERENTIAL or MODE_ESTIMATED */
			char mode;
		};
		
		
		/**
			@var GpsInfo
			@brief Global variable GPS Information.
			@details This Global variable of type GpsInfo_s is used to store the processed GPS information.
		*/
		GpsInfo_s GpsInfo;
		
		
		float GetDist(float Lat1, float Lon1, float Lat2, float Lon2);
		int GetBearing(float Lat1, float Lon1, float Lat2, float Lon2);
		float degreeToRadian(float degree);
		float radianToDegree(float radian);
		int ProcessNmeaStr(char *nmea, int Len);
		void ProcessNmea_RMC(char *nmea, int Len);
		float dmtodd(char *dm, char NSEW);
		
		//date time
		boolean nttots(char *timestr, time_s &timeReturn);
		void gettimestr(char *time);
		boolean ndtods(char *datestr, int fromtype, date_s &dateReturn);
		void getdatestr(char *date);
		
		//Speed Conversion
		float ktstokmh(float kts);
		float ktstomph(float kts);
		
#ifdef PMTKCHN_ENABLE

		/** 
			@struct channel_s gps.h "gps.h"
			@brief channel information
			@details This struct is used to work with the channel information provided by the NMEA type string from MTK device $PMTKCHN.
		*/
		struct channel_s
		{
			/** @var svid
			Space Vehicle Id */
			uint8_t svid;
			
			/** @var snr
			Signal to Noise Ratio */
			uint8_t snr;	// Signal to Noise Ratio
			
			/** @var status
			Channel status. Use the define STATUS_CHN_IDLE, STATUS_CHN_SEARCHING and STATUS_CHN_TRACKING */
			uint8_t status;	// 0: Idle / 1: Searching / 2: Tracking
		};
		
		/**
			@var chan
			@brief Global Channel Info
			@details This Global variable is used to store the channel information extracted from the NMEA style MTK device $PMTKCHN string.
			By default the size of the array is 66. The array size can be overrided in gps_setup.h using the TOTAL_CHANNEL define.
		*/
		channel_s chan[TOTAL_CHANNEL];
		void ProcessNmea_PMTKCHN(char *nmea, int Len);
#endif	


#ifdef GPZDA_ENABLE
		void ProcessNmea_ZDA(char *nmea, int Len);
#endif	


#ifdef CHECKSUM_ENABLE
		boolean CheckNmeaChecksum(char *nmea, int Len);
		int getCheckSum(char *string);
#endif	

	private:
	/** 
		@var GotZda
		@brief $GPZDA marker
		@details This boolean variable get set and stay to true whenever a NMEA $GPZDA string is processed. 
		It is used internaly for the librarie to know where to get the time and date data.
	*/
	boolean GotZda;	
		
};

#endif